package com.jy.api.service.impl;

import com.jy.api.dao.*;
import com.jy.api.domain.*;
import com.jy.api.service.InventoryService;
import com.jy.api.service.StockReceiptSerivce;
import com.jy.api.service.StockTransactionService;
import com.jy.api.signUpReq.InvStatisticsRes;
import com.jy.api.signUpReq.stock.*;
import com.jy.api.util.MyDateUtils;
import com.jy.api.util.Result;
import com.jy.api.vo.stock.InventoryDataVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.Date;

/**
 * Created by hanxi on 2018/7/5.
 */

@Slf4j
@Service
public class InventoryServiceImpl implements InventoryService {

    @Autowired
    InventoryDao inventoryDao;
    @Autowired
    StockTransactionService stockTransactionService;
    @Autowired
    private ProductDao productDao;
    @Autowired
    private StoreDao storeDao;
    @Autowired
    private EmployeeDao employeeDao;
    @Autowired
    private StockCheckOrderDao stockCheckOrderDao;
    @Autowired
    private StockTransactionDao stockTransactionDao;
    @Autowired
    private StockReceiptSerivce stockReceiptSerivce;
    @Autowired
    private StockReceiptDao stockReceiptDao;


    /**
     * @param storeId
     * @param page
     * @return
     */

    @Override
    public Page<Inventory> findByStoreId(String storeId, Pageable page) {
        Page<Inventory> byStoreIdAndNameLike = inventoryDao.findByStoreIdAndEnabled(storeId, true, page);
        return byStoreIdAndNameLike;
    }

    /**
     * 查询店铺
     *
     * @param storeId
     * @param page
     * @return
     */
    @Override
    public Page<Product> findByStoreIdAndIsStockEnable(String storeId, Pageable page) {
        Page<Product> list = productDao.findListByStockEnabledAndEnabledAndStoreId(true, true, storeId, page);
        return list;
    }

    /**
     * 修改进货价格
     *
     * @param inventoryDataVo
     */
    @Override
    @Transactional
    public void updateByStoreId(InventoryDataVo inventoryDataVo) {
        Inventory one = inventoryDao.findById(inventoryDataVo.getId());
        if (one != null) {
            one.setPurchasePrice(inventoryDataVo.getPrice());
            inventoryDao.save(one);
        }


    }

    /**
     * 通过id查库存ID
     *
     * @param id
     * @param pageable
     * @return
     */
    @Override
    public Page<Inventory> findByProductId(String id, Pageable pageable) {
        Page<Inventory> page = inventoryDao.findByEnabledAndProductId(true, id, pageable);
        return page;
    }


    @Override
    public List<Inventory> findByPId(String id) {
        return inventoryDao.findByEnabledAndProductId(true, id);
    }

    /**
     * 通过商品ID查询吧台商品
     *
     * @param id
     * @return
     */
    @Override
    public Page<Product> findCountByProduct(String id, Pageable pageable) {
        Page<Product> list = productDao.findListByStockEnabledAndEnabledAndId(true, true, id, pageable);
        return list;
    }


    /**
     * 仓库入库
     *
     * @param req
     * @return
     */
    @Override
    @Transactional
    public Result stockIn(InventoryInReq req) {
        StockReceipt stockReceipt = stockReceiptSerivce.save(req);
        Store store = storeDao.findOne(req.getStoreId());
        List<StockChangeTransaction> stockInTransactions = new ArrayList<>();
        List<StockChangeTransaction> stockoutTransactions = new ArrayList<>();
        if (store == null) {
            return new Result(400, "无该店铺信息");
        }
        Employee employee = employeeDao.findOne(req.getOperatorId());
        if (employee == null) {
            return new Result(400, "无该操作人的信息");
        }
        if (req.getStockSource().equals(StockChangeReason.INNER_IN)) {
            List<InventoryInReq.Inventore> list = req.getInventores();
            for (InventoryInReq.Inventore in : list) {
                Product product = productDao.findOne(in.getProductId());
                if (product.getQuantity() - (in.getQuantity() * in.getCapacity()) < 0) {
                    return new Result(400, "入库失败，吧台商品，" + product.getName() + "库存不足");
                }
            }
            for (InventoryInReq.Inventore in : list) {
                Inventory inventory = inventoryDao.findById(in.getInvId());
                Product product = productDao.findOne(in.getProductId());
                inventory.setQuantity(inventory.getQuantity() + in.getQuantity());
                product.setQuantity(product.getQuantity() - (in.getQuantity() * in.getCapacity()));
                inventoryDao.save(inventory);
                productDao.save(product);
                //这里保存仓库入库记录
                StockChangeTransaction stockTransaction = new StockChangeTransaction(in,
               /*店铺id*/req.getStoreId(),/*入库*/ StockType.STOCK_IN,/*出入库原因*/ StockChangeReason.INNER_IN,
                      /*操作人的id*/ req.getOperatorId(), /*操作人的名字*/req.getOperatorName(), null, /*操作人的备注*/ req.getNotes(), in.getQuantity());
                stockInTransactions.add(stockTransaction);
                //保存吧台的出库记录
                StockChangeTransaction stockOutTransaction = new StockChangeTransaction(product, in,
               /*店铺id*/req.getStoreId(), StockType.STOCK_OUT, StockChangeReason.INNER_OUT,/*操作人的id*/ req.getOperatorId(), /*操作人的名字*/req.getOperatorName(),/*操作人的备注*/ req.getNotes());
                stockoutTransactions.add(stockOutTransaction);
            }
            stockTransactionDao.save(stockInTransactions);
            stockTransactionDao.save(stockoutTransactions);
            return new Result(200, "入库成功");
        } else {
            List<InventoryInReq.Inventore> list = req.getInventores();
            for (InventoryInReq.Inventore in : list) {
                Inventory inventory = inventoryDao.findById(in.getInvId());
                inventory.setQuantity(inventory.getQuantity() + in.getQuantity());
                inventoryDao.save(inventory);
            }
            stockTransactionService.addStockIn(req, stockReceipt.getId());
            return new Result(200, "入库成功");
        }

    }

    /**
     * 仓库出库
     *
     * @param inReq
     * @return
     */
    @Override
    @Transactional
    public Result stockOut(InventoryInReq inReq) {
        StockReceipt stockReceipt = stockReceiptSerivce.out(inReq);
        List<InventoryInReq.Inventore> list = inReq.getInventores();
        /**
         * 对仓库库存减少，对吧台库存增加
         */
        if (inReq.getStockSource().equals(StockChangeReason.INNER_OUT)) {
            for (InventoryInReq.Inventore in : list) {
                Inventory inventory = inventoryDao.findById(in.getInvId());
                Integer integer = inventory.getQuantity() - in.getQuantity();
                if (integer < 0) {
                    return new Result(400, "出库失败" + inventory.getName() + "库存不足");
                }
            }
            for (InventoryInReq.Inventore in : list) {
                Inventory inventory = inventoryDao.findById(in.getInvId());
                inventory.setQuantity(inventory.getQuantity() - in.getQuantity());
                inventoryDao.save(inventory);
                Product product = productDao.findOne(in.getProductId());
                product.setQuantity(product.getQuantity() + (in.getQuantity() * in.getCapacity()));
                productDao.save(product);
                //仓库出库记录
                StockChangeTransaction stockTransaction = new StockChangeTransaction(in,
               /*店铺id*/inReq.getStoreId(),/*出库*/ StockType.STOCK_OUT,/*出入库原因*/ StockChangeReason.INNER_OUT,
                     /*操作人的id*/ inReq.getOperatorId(), /*操作人的名字*/inReq.getOperatorName(), null,/*操作人的备注*/ inReq.getNotes(), in.getQuantity());
                stockTransactionDao.save(stockTransaction);
                //保存吧台的入库记录
                StockChangeTransaction stockinTransaction = new StockChangeTransaction(product, in,
               /*店铺id*/inReq.getStoreId(), StockType.STOCK_IN, StockChangeReason.INNER_IN,/*操作人的id*/ inReq.getOperatorId(), /*操作人的名字*/inReq.getOperatorName(),/*操作人的备注*/ inReq.getNotes());
                stockTransactionDao.save(stockinTransaction);
            }
            return new Result(200, "出库成功");
        } else {
            for (InventoryInReq.Inventore in : list) {
                Inventory inventory = inventoryDao.findById(in.getInvId());
                Integer integer = inventory.getQuantity() - in.getQuantity();
                if (integer < 0) {
                    return new Result(400, "出库失败," + inventory.getName() + "库存不足");
                }
            }
            for (InventoryInReq.Inventore in : list) {
                Inventory inventory = inventoryDao.findById(in.getInvId());
                StockChangeTransaction stockTransaction = new StockChangeTransaction(in,
               /*店铺id*/inReq.getStoreId(),/*出库*/ StockType.STOCK_OUT,/*出入库原因*/ inReq.getStockSource(),
                   /*操作人的id*/ inReq.getOperatorId(), /*操作人的名字*/inReq.getOperatorName(), String.valueOf(stockReceipt.getId()),/*操作人的备注*/ inReq.getNotes(), in.getQuantity());
                inventory.setQuantity(inventory.getQuantity() - in.getQuantity());
                inventoryDao.save(inventory);
                stockTransactionDao.save(stockTransaction);
            }
            return new Result(200, "出库成功");
        }
    }


    @Override
    @Transactional
    public void addNewCapacity(InventoryReqData inventoryReqData) {
        Inventory in = inventoryDao.findByProductIdAndCapacity(inventoryReqData.getProductId(), inventoryReqData.getCapacity());
        Product product = productDao.findOne(in.getProductId());
        if (in == null) {
            Inventory inventory = new Inventory(inventoryReqData, 0, 0.0);
            inventoryDao.save(inventory);
            return;
        } else {
            if (!in.isEnabled()) {
                in.setName(product.getName());
                in.setEnabled(true);
                in.setPurchasePrice(0.0);
                in.setQuantity(0);
                inventoryDao.save(in);
            }
        }


    }

    /**
     * 通过商品Id查询规格
     *
     * @param productId
     * @return
     */
    @Override
    public List<Map<String, Object>> findByInvProductId(String productId, String storeId) {
        List<Object> list = inventoryDao.findInvByProductId(productId, true, storeId);
        List<Map<String, Object>> ob = new ArrayList<>();
        for (Object o : list) {
            Object[] objects1 = (Object[]) o;
            HashMap<String, Object> map = new HashMap<>();
            map.put("id", objects1[0]);
            map.put("capacity", objects1[1]);
            ob.add(map);
        }
        return ob;
    }

    /**
     * 通过id删除inv
     *
     * @param id
     * @throws Exception
     */
    @Override
    @Transactional
    public Result deleteByInvId(long id) {
        Inventory inventory = inventoryDao.findById(id);
        if (inventory != null) {
            if (inventory.getQuantity() == 0) {
                inventory.setEnabled(false);
                inventoryDao.save(inventory);
                return new Result(200, "删除成功");
            } else {
                return new Result(400, "删除失败，该规格下还有商品");
            }

        }
        return new Result(400, "该规格不存在");
    }

    /**
     * 通过店铺id查询库存列表
     *
     * @param storeId
     * @param
     * @return
     */
    @Override
    public List<Inventory> findListByStoreId(String storeId) {
        List<Inventory> res = inventoryDao.findListByEnabledAndStoreId(true, storeId);
        return res;
    }

    /**
     * 盘点记录
     *
     * @param req
     * @return
     */
    @Override
    @Transactional
    public Result checkInOrOut(InventoryCheckReq req) {
        //保存盘点主记录
        StockCheck stockCheck = new StockCheck(req, StockLevel.WAREHOUSE);
        List<StockCheckTransaction> list = new ArrayList<>();
        //盘点更改库存
        if (null == storeDao.findOne(req.getStoreId())) {
            return new Result(400, "无店铺信息");
        }
        if (null == employeeDao.findOne(req.getOperatorId())) {
            return new Result(400, "无改店员信息");
        }
        for (InventoryCheckReq.CheckInventory in : req.getCheckInventories()) {
            String s = in.checkSockType();
            if (s.equals("NO")) {
                /**
                 * 数量相等，只执行生成盘点记录
                 */
                //生成盘点记录
                StockCheckTransaction s1 = new StockCheckTransaction(in, req.getStoreId(), req.getOperatorId(), req.getOperatorName());
                list.add(s1);
            } else if (s.equals("CHECK-OUT")) {
                /**
                 * 数量不等，执行更改库存操作，并且生成出库记录
                 */
                Inventory inventory = inventoryDao.findById(in.getInvId());
                inventory.setQuantity(in.getCheckWholeQty());
                inventoryDao.save(inventory);
                //生成盘点记录
                StockCheckTransaction s1 = new StockCheckTransaction(in, req.getStoreId(), req.getOperatorId(), req.getOperatorName());
                list.add(s1);
                //生成changeTransaction
                Integer i = Math.abs(in.getCheckWholeQty() - in.getAccurateWholeQty());
                StockChangeTransaction changeTransaction = new StockChangeTransaction(in, req.getStoreId(), StockType.STOCK_OUT, StockChangeReason.CHECK_OUT, null, req.getOperatorId(), req.getOperatorName(), in.getNotes(), i);
                stockTransactionDao.save(changeTransaction);

            } else {
                /**
                 * 数量不等，执行更改库存操作，并且生成入库记录
                 */
                Inventory inventory = inventoryDao.findById(in.getInvId());
                inventory.setQuantity(in.getCheckWholeQty());
                inventoryDao.save(inventory);
                //生成盘点记录
                StockCheckTransaction s1 = new StockCheckTransaction(in, req.getStoreId(), req.getOperatorId(), req.getOperatorName());
                list.add(s1);
                //生成changeTransaction
                Integer i = Math.abs(in.getCheckWholeQty() - in.getAccurateWholeQty());
                StockChangeTransaction changeTransaction = new StockChangeTransaction(in, req.getStoreId(), StockType.STOCK_IN, StockChangeReason.CHECK_IN, null, req.getOperatorId(), req.getOperatorName(), in.getNotes(), i);
                stockTransactionDao.save(changeTransaction);

            }
        }
        stockCheck.setItems(list);
        stockCheckOrderDao.save(stockCheck);
        return new Result(200, "盘点成功");
    }

    /**
     * 库存记录组合查询
     *
     * @param req
     * @param pageable
     * @return
     */

    @Override
    public Page<StockChangeTransaction> findByProductIdAndCapacity(InventorySerachReq req, Pageable pageable) {
        Page<StockChangeTransaction> p = null;
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -35);
        if ((StringUtils.equals(req.getReason().toString(), "ALL") && StringUtils.equals(req.getType().toString(), "ALL")) && null == req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(),StockLevel.WAREHOUSE, pageable);
        } else if ((StringUtils.equals(req.getReason().toString(), "ALL") && !StringUtils.equals(req.getType().toString(), "ALL")) && null == req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndTypeAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(), req.getType(),StockLevel.WAREHOUSE,  pageable);
        } else if ((!StringUtils.equals(req.getReason().toString(), "ALL") && StringUtils.equals(req.getType().toString(), "ALL")) && null == req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndSourceAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(), req.getReason(),StockLevel.WAREHOUSE,  pageable);
        } else if ((!StringUtils.equals(req.getReason().toString(), "ALL") && !StringUtils.equals(req.getType().toString(), "ALL")) && null == req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndSourceAndTypeAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(), req.getReason(), req.getType(),StockLevel.WAREHOUSE,  pageable);
        } else if ((!StringUtils.equals(req.getReason().toString(), "ALL") && StringUtils.equals(req.getType().toString(), "ALL")) && null != req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndSourceAndSkuIdAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(), req.getReason(), req.getInvId(), StockLevel.WAREHOUSE, pageable);
        } else if ((StringUtils.equals(req.getReason().toString(), "ALL") && !StringUtils.equals(req.getType().toString(), "ALL")) && null != req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndTypeAndSkuIdAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(), req.getType(), req.getInvId(),StockLevel.WAREHOUSE,  pageable);
        } else if ((!StringUtils.equals(req.getReason().toString(), "ALL") && !StringUtils.equals(req.getType().toString(), "ALL")) && null != req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndTypeAndSkuIdAndSourceAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(), req.getType(), req.getInvId(), req.getReason(),StockLevel.WAREHOUSE,  pageable);
        }else if ((StringUtils.equals(req.getReason().toString(), "ALL") && StringUtils.equals(req.getType().toString(), "ALL")) && null != req.getInvId()) {
            p = stockTransactionDao.findAllByStoreIdAndAddTimeGreaterThanEqualAndSkuIdAndStockLevelOrderByAddTimeDesc(req.getStoreId(), calendar.getTime(),req.getInvId(),StockLevel.WAREHOUSE,  pageable);
        }
      /*  StockChangeTransaction transaction = new StockChangeTransaction(req);
        ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("id", "quantity");
         stockTransactionDao.findAll(Example.of(transaction, matcher), pageable)*/
        return p;
    }

    @Override
    public List<Product> findByProduct(String productId) {
        return productDao.findListByStockEnabledAndEnabledAndId(true, true, productId);
    }

    @Override
    @Transactional
    public Map<String, Object> saveCa(CapReq req) {
        Map<String, Object> map = new HashMap<>();
        Inventory inventory = inventoryDao.findByProductIdAndCapacity(req.getProductId(), req.getCapacity());
        if (null == inventory) {
            Inventory in = new Inventory(req);
            Inventory i = inventoryDao.save(in);
            map.put("data", i);
            map.put("msg", "操作成功");
        } else {
            if (!inventory.isEnabled()) {
                inventory.setEnabled(true);
                inventory.setPurchasePrice(req.getPurchasePrice());
                inventory.setQuantity(0);
                Inventory i = inventoryDao.save(inventory);
                map.put("data", i);
                map.put("msg", "操作成功");
            } else {
                List list = new ArrayList();
                map.put("data", list);
                map.put("msg", "该规格已存在，请核实！");
            }
        }
        return map;
    }

    @Override
    public Page<StockChangeTransaction> findStatisticsList(String storeId, int year, int month, Pageable pageable) {
        String date = year + "-" + month;
        Date start = MyDateUtils.getMinMonthDate(date);
        Date end = MyDateUtils.getMaxMonthDate(date);
        Page<StockChangeTransaction> stockChangeTransactions = stockTransactionDao.findByStoreIdAndAddTimeBetweenAndTypeAndSource(storeId, start, end, StockType.STOCK_IN, StockChangeReason.PURCHASE_IN, pageable);
        return stockChangeTransactions;
    }

    @Override
    public InvStatisticsRes getStatistics(String storeId, String year, String month) {
        String date = year + "-" + month;
        InvStatisticsRes res = new InvStatisticsRes();
        List<Object[]> objects;
        objects = stockReceiptDao.findStatistics(storeId, "STOCK_IN", "PURCHASE_IN", date);
        for (Object[] obj : objects) {
            if (null == obj[0] || null == obj[1]) {
                res.setAmount("0.0");
            } else {
                res.setAmount(obj[0].toString());
                res.setCount(obj[1].toString());
            }
        }
        return res;
    }


}
